// **************************************************************
// Com ++ Framework by the C++ World
// Please report defects: mailto:compp@cplusplusworld.com
// Please visit: http://www.cplusplusworld.com/socketlibrary.html
// **************************************************************


#include <sys/types.h>
#include <sys/ipc.h>

#include <sys/shm.h>

#include "ComPlusPlus/ShMem.h"
#include "SysPlusPlus/ComException.h"
#include "SysPlusPlus/syscall.h"


compp::ShMem::ShMem( const int key, const int size, const int mode, bool exclusive  ) {

  Addr = NULL; 
  DestroyInDestructor = false;
  int locmodes = mode | IPC_CREAT;
  if ( exclusive ) {
    locmodes = locmodes | IPC_EXCL;
  }
  
  if ( -1 == ( ShMemId = syspp::Call::ShmGet( key, size, locmodes ) ) )
    throw syspp::ComException ( "Cannot create shared memory segment");
  
}

compp::ShMem::ShMem( const int key, const int size, const int mode ) {
  
  Addr = NULL;
  DestroyInDestructor = false;
  if ( -1 == ( ShMemId = syspp::Call::ShmGet( key, size, mode ) ) )
    throw syspp::ComException ( "Cannot create shared memory segment");

}

compp::ShMem::~ShMem() {
  
  Detach();
  if ( DestroyInDestructor )
    Destroy ();
}

int  compp::ShMem::getId() {
  return ShMemId;
}

void* compp::ShMem::getStartAddr ( ) {

  return Addr;
}


void compp::ShMem::Attach() {

  Addr = syspp::Call::ShmAt(ShMemId, NULL, 0 );
  if ( Addr == (void *) -1 ) {
    throw syspp::ComException ( "Cannot attache shared memory segment");
  }

}

void compp::ShMem::Detach() {

  if ( -1 == syspp::Call::ShmDt(Addr) ) {
    throw syspp::ComException ( "Cannot detach shared memory segment");
  }
   
  Addr = NULL;

}

void compp::ShMem::Destroy() {
  struct shmid_ds buffer;

  if ( -1 ==  shmctl(ShMemId, IPC_RMID, &buffer) ) {
    throw syspp::ComException ( "Cannot mark shared memory segment for deletion.");
  }

}



void compp::ShMem::AutoDestroy( const bool on ) {

  if ( on ) 
    DestroyInDestructor = true;
  else
    DestroyInDestructor = false;
}
